﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

using LowLevelGraphics.Types.Interval;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Use this filter to let it follow a path. This is no scanline or per pixel approach.
    /// Each pixel that will be followed on a path while the colors are in tolerance
    /// 
    /// The seed point determines where to start
    /// 
    /// This works with colored pics
    /// </summary>
    public class PixelPathFollower : BaseImageFilter
    {
        protected float m_fTolerance = 1000;
        protected Point m_ptSeed = new Point(0,0);
        protected Point[] m_aPoint = Definitions.EnvironmentPointListClockwise.ToArray();
        protected Color m_ColorToReplace = Definitions.Red;
        protected FloatInterval m_fValueRange = new FloatInterval(0, 0xFFFFFF);

        /// <summary>
        /// Initializes a new instance of the <see cref="PixelPathFollower"/> class.
        /// </summary>
        public PixelPathFollower()
        {
            M_PROCESSING_MODE = PROCESSING_MODE.ToIntRgb;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="PixelPathFollower"/> class.
        /// </summary>
        /// <param name="_pixelPathFollower">The _pixel path follower.</param>
        internal PixelPathFollower(PixelPathFollower _pixelPathFollower)
        {
        }

        /// <summary>
        /// Gets or sets the color to replace.
        /// </summary>
        /// <value>The color to replace.</value>
        public Color ColorToReplace
        {
            get { return m_ColorToReplace; }
            set { m_ColorToReplace = value; }
        }

        /// <summary>
        /// Gets or sets the tolerance.
        /// </summary>
        /// <value>The tolerance.</value>
        public float Tolerance
        {
            get { return m_fTolerance; }
            set { m_fTolerance = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public FloatInterval Interval
        {
            get { return m_fValueRange; }
            set { m_fValueRange = value; }
        }

        /// <summary>
        /// Gets or sets the seed.
        /// </summary>
        /// <value>The seed.</value>
        public Point Seed
        {
            get { return m_ptSeed; }
            set { m_ptSeed = value; }
        }

        /// <summary>
        /// Execute this Filter
        /// A Debug Statement is written if a concrete Filter is called
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int x = 0;
            int y = 0;
            int nHeight = _bitmap.Height;
            int nWidth = _bitmap.Width;
            Point NoPoint = new Point(-1, -1);

            bool[,] bMarkAll = new bool[nWidth, nHeight];
            float fValue = 0.0f;
            float fValueTemp = 0.0f;
            ColorCalculation calc = Definitions.ColorCalculationDictionaryProcessingMode[M_PROCESSING_MODE];
            
            Point ptStartNext = m_ptSeed;
            if (m_ptSeed == NoPoint)
            {
                ptStartNext = new Point(_bitmap.Width / 2, _bitmap.Height / 2);
            }

            bool bMarkedAll = false;
            int nCount = 0;
            int nCountMax = nHeight * nWidth;


            int nXTemp = 0;
            int nYTemp = 0;
            bool bFound = false;

            for (y = 0; y < nHeight; y++)
            {
                for (x = 0; x < nWidth; x++)
                {
                    ptStartNext = new Point(x, y);

                a:
                    Color _bitmapGetPixel = _bitmap.GetPixel(ptStartNext);
                    //Get value

                    fValue = calc(_bitmapGetPixel);

                    if (!m_fValueRange.Contains(fValue)) continue;

                    //Get value of surrounding pixels
                    foreach (Point ptPoint in m_aPoint)
                    {
                        nXTemp = ptPoint.X + ptStartNext.X;
                        nYTemp = ptPoint.Y + ptStartNext.Y;

                        if (nXTemp < 0 || nYTemp < 0 || nXTemp > nWidth - 1 || nYTemp > nHeight - 1)
                        {
                            continue;
                        }

                        if (bMarkAll[nXTemp, nYTemp]) continue;

                        //compare
                        fValueTemp = calc(_bitmap.GetPixel(nXTemp, nYTemp));
                        if (Math.Abs(fValue - fValueTemp) <= m_fTolerance)
                        {
                            ptStartNext = new Point(nXTemp, nYTemp);
                            bMarkAll[nXTemp, nYTemp] = true;
                            _bitmap.SetPixel(nXTemp, nYTemp, m_ColorToReplace);
                            goto a;
                        }
                    }
                }
            }
            return _bitmap;
        }

        /// <summary>
        /// This is used to clone a filter, each filter must implement it's own clone functionality
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new PixelPathFollower(this);
        }
    }
}
